ํ์ด์ฌ ๋์คํฌ๋ฆฝํฐ ํ๋กํ ์ฝ์ ๋ง์คํฐํ์ฌ ๊ฐ๋ ฅํ ์์ฑ ์ ๊ทผ ์ ์ด, ๊ณ ๊ธ ๋ฐ์ดํฐ ์ ํจ์ฑ ๊ฒ์ฌ, ๊ทธ๋ฆฌ๊ณ ๋ ๊น๋ํ๊ณ ์ ์ง๋ณด์ํ๊ธฐ ์ฌ์ด ์ฝ๋๋ฅผ ์์ฑํ์ธ์. ์ค์ฉ์ ์ธ ์์ ์ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ํฌํจํฉ๋๋ค.
ํ์ด์ฌ ๋์คํฌ๋ฆฝํฐ ํ๋กํ ์ฝ: ์์ฑ ์ ๊ทผ ์ ์ด ๋ฐ ๋ฐ์ดํฐ ์ ํจ์ฑ ๊ฒ์ฌ ๋ง์คํฐํ๊ธฐ
ํ์ด์ฌ ๋์คํฌ๋ฆฝํฐ ํ๋กํ ์ฝ์ ํด๋์ค์ ์์ฑ ์ ๊ทผ ๋ฐ ์์ ์ ์ธ๋ฐํ๊ฒ ์ ์ดํ ์ ์๊ฒ ํด์ฃผ๋ ๊ฐ๋ ฅํ์ง๋ง ์ข ์ข ๊ฐ๊ณผ๋๋ ๊ธฐ๋ฅ์ ๋๋ค. ์ด๋ ์ ๊ตํ ๋ฐ์ดํฐ ์ ํจ์ฑ ๊ฒ์ฌ์ ์์ฑ ๊ด๋ฆฌ๋ฅผ ๊ตฌํํ๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํ์ฌ ๋ ๊น๋ํ๊ณ , ๊ฒฌ๊ณ ํ๋ฉฐ, ์ ์ง๋ณด์ํ๊ธฐ ์ฌ์ด ์ฝ๋๋ฅผ ์์ฑํ๋๋ก ์ด๋๋๋ค. ์ด ์ข ํฉ ๊ฐ์ด๋์์๋ ๋์คํฌ๋ฆฝํฐ ํ๋กํ ์ฝ์ ํต์ฌ ๊ฐ๋ , ์ค์ ์ ์ฉ ์ฌ๋ก, ๊ทธ๋ฆฌ๊ณ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ํ๊ตฌํ๋ฉฐ ๊ทธ ๋ณต์ก์ฑ์ ๊น์ด ํํค์ณ ๋ณด๊ฒ ์ต๋๋ค.
๋์คํฌ๋ฆฝํฐ ์ดํดํ๊ธฐ
ํต์ฌ์ ์ผ๋ก, ๋์คํฌ๋ฆฝํฐ ํ๋กํ ์ฝ์ ์์ฑ์ด ๋์คํฌ๋ฆฝํฐ๋ผ๊ณ ๋ถ๋ฆฌ๋ ํน๋ณํ ์ข ๋ฅ์ ๊ฐ์ฒด์ผ ๋ ์์ฑ ์ ๊ทผ์ด ์ด๋ป๊ฒ ์ฒ๋ฆฌ๋๋์ง๋ฅผ ์ ์ํฉ๋๋ค. ๋์คํฌ๋ฆฝํฐ๋ ๋ค์ ๋ฉ์๋ ์ค ํ๋ ์ด์์ ๊ตฌํํ๋ ํด๋์ค์ ๋๋ค:
- `__get__(self, instance, owner)`: ๋์คํฌ๋ฆฝํฐ์ ๊ฐ์ ์ ๊ทผํ ๋ ํธ์ถ๋ฉ๋๋ค.
- `__set__(self, instance, value)`: ๋์คํฌ๋ฆฝํฐ์ ๊ฐ์ ์ค์ ํ ๋ ํธ์ถ๋ฉ๋๋ค.
- `__delete__(self, instance)`: ๋์คํฌ๋ฆฝํฐ์ ๊ฐ์ ์ญ์ ํ ๋ ํธ์ถ๋ฉ๋๋ค.
ํด๋์ค ์ธ์คํด์ค์ ์์ฑ์ด ๋์คํฌ๋ฆฝํฐ์ผ ๋, ํ์ด์ฌ์ ๊ธฐ๋ณธ ์์ฑ์ ์ง์ ์ ๊ทผํ๋ ๋์ ์ด๋ฌํ ๋ฉ์๋๋ค์ ์๋์ผ๋ก ํธ์ถํฉ๋๋ค. ์ด ๊ฐ๋ก์ฑ๊ธฐ ๋ฉ์ปค๋์ฆ์ ์์ฑ ์ ๊ทผ ์ ์ด ๋ฐ ๋ฐ์ดํฐ ์ ํจ์ฑ ๊ฒ์ฌ์ ๊ธฐ๋ฐ์ ์ ๊ณตํฉ๋๋ค.
๋ฐ์ดํฐ ๋์คํฌ๋ฆฝํฐ vs. ๋น-๋ฐ์ดํฐ ๋์คํฌ๋ฆฝํฐ
๋์คํฌ๋ฆฝํฐ๋ ๋ ๊ฐ์ง ๋ฒ์ฃผ๋ก ๋ ๋ถ๋ฅ๋ฉ๋๋ค:
- ๋ฐ์ดํฐ ๋์คํฌ๋ฆฝํฐ: `__get__`๊ณผ `__set__`์ ๋ชจ๋ ๊ตฌํํฉ๋๋ค(์ ํ์ ์ผ๋ก `__delete__`๋ ๊ฐ๋ฅ). ์ด๋ค์ ๊ฐ์ ์ด๋ฆ์ ์ธ์คํด์ค ์์ฑ๋ณด๋ค ๋์ ์ฐ์ ์์๋ฅผ ๊ฐ์ง๋๋ค. ์ฆ, ๋ฐ์ดํฐ ๋์คํฌ๋ฆฝํฐ์ธ ์์ฑ์ ์ ๊ทผํ ๋, ์ธ์คํด์ค์ ๊ฐ์ ์ด๋ฆ์ ์์ฑ์ด ์๋๋ผ๋ ํญ์ ๋์คํฌ๋ฆฝํฐ์ `__get__` ๋ฉ์๋๊ฐ ํธ์ถ๋ฉ๋๋ค.
- ๋น-๋ฐ์ดํฐ ๋์คํฌ๋ฆฝํฐ: `__get__`๋ง ๊ตฌํํฉ๋๋ค. ์ด๋ค์ ์ธ์คํด์ค ์์ฑ๋ณด๋ค ๋ฎ์ ์ฐ์ ์์๋ฅผ ๊ฐ์ง๋๋ค. ๋ง์ฝ ์ธ์คํด์ค์ ๊ฐ์ ์ด๋ฆ์ ์์ฑ์ด ์๋ค๋ฉด, ๋์คํฌ๋ฆฝํฐ์ `__get__` ๋ฉ์๋๋ฅผ ํธ์ถํ๋ ๋์ ํด๋น ์์ฑ์ด ๋ฐํ๋ฉ๋๋ค. ์ด๋ ์ฝ๊ธฐ ์ ์ฉ ์์ฑ์ ๊ตฌํํ๋ ๊ฒ๊ณผ ๊ฐ์ ์์ ์ ์ ์ฉํ๊ฒ ๋ง๋ญ๋๋ค.
ํต์ฌ์ ์ธ ์ฐจ์ด๋ `__set__` ๋ฉ์๋์ ์ ๋ฌด์ ์์ต๋๋ค. ์ด ๋ฉ์๋๊ฐ ์์ผ๋ฉด ๋์คํฌ๋ฆฝํฐ๋ ๋น-๋ฐ์ดํฐ ๋์คํฌ๋ฆฝํฐ๊ฐ ๋ฉ๋๋ค.
๋์คํฌ๋ฆฝํฐ ์ฌ์ฉ์ ์ค์ ์์
๋ช ๊ฐ์ง ์ค์ ์์ ๋ฅผ ํตํด ๋์คํฌ๋ฆฝํฐ์ ๊ฐ๋ ฅํจ์ ์ค๋ช ํด ๋ณด๊ฒ ์ต๋๋ค.
์์ 1: ํ์ ๊ฒ์ฌ
ํน์ ์์ฑ์ด ํญ์ ํน์ ํ์ ์ ๊ฐ์ ์ ์งํ๋๋ก ํ๊ณ ์ถ๋ค๊ณ ๊ฐ์ ํด ๋ด ์๋ค. ๋์คํฌ๋ฆฝํฐ๋ ์ด๋ฌํ ํ์ ์ ์ฝ ์กฐ๊ฑด์ ๊ฐ์ ํ ์ ์์ต๋๋ค:
class Typed:
def __init__(self, name, expected_type):
self.name = name
self.expected_type = expected_type
def __get__(self, instance, owner):
if instance is None:
return self # ํด๋์ค ์์ฒด์์ ์ ๊ทผ
return instance.__dict__[self.name]
def __set__(self, instance, value):
if not isinstance(value, self.expected_type):
raise TypeError(f"Expected {self.expected_type}, got {type(value)}")
instance.__dict__[self.name] = value
class Person:
name = Typed('name', str)
age = Typed('age', int)
def __init__(self, name, age):
self.name = name
self.age = age
# ์ฌ์ฉ๋ฒ:
person = Person("Alice", 30)
print(person.name) # ์ถ๋ ฅ: Alice
print(person.age) # ์ถ๋ ฅ: 30
try:
person.age = "thirty"
except TypeError as e:
print(e) # ์ถ๋ ฅ: Expected <class 'int'>, got <class 'str'>
์ด ์์ ์์ `Typed` ๋์คํฌ๋ฆฝํฐ๋ `Person` ํด๋์ค์ `name`๊ณผ `age` ์์ฑ์ ๋ํ ํ์ ๊ฒ์ฌ๋ฅผ ๊ฐ์ ํฉ๋๋ค. ๋ง์ฝ ์๋ชป๋ ํ์ ์ ๊ฐ์ ํ ๋นํ๋ ค๊ณ ํ๋ฉด `TypeError`๊ฐ ๋ฐ์ํฉ๋๋ค. ์ด๋ ๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ์ ํฅ์์ํค๊ณ ์ฝ๋ ํ๋ฐ๋ถ์์ ๋ฐ์ํ ์ ์๋ ์๊ธฐ์น ์์ ์ค๋ฅ๋ฅผ ๋ฐฉ์งํฉ๋๋ค.
์์ 2: ๋ฐ์ดํฐ ์ ํจ์ฑ ๊ฒ์ฌ
ํ์ ๊ฒ์ฌ๋ฅผ ๋์ด์, ๋์คํฌ๋ฆฝํฐ๋ ๋ ๋ณต์กํ ๋ฐ์ดํฐ ์ ํจ์ฑ ๊ฒ์ฌ๋ ์ํํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ์ซ์ ๊ฐ์ด ํน์ ๋ฒ์ ๋ด์ ์๋์ง ํ์ธํ๊ณ ์ถ์ ์ ์์ต๋๋ค:
class Sized:
def __init__(self, name, min_value, max_value):
self.name = name
self.min_value = min_value
self.max_value = max_value
def __get__(self, instance, owner):
if instance is None:
return self
return instance.__dict__[self.name]
def __set__(self, instance, value):
if not isinstance(value, (int, float)):
raise TypeError("Value must be a number")
if not (self.min_value <= value <= self.max_value):
raise ValueError(f"Value must be between {self.min_value} and {self.max_value}")
instance.__dict__[self.name] = value
class Product:
price = Sized('price', 0, 1000)
def __init__(self, price):
self.price = price
# ์ฌ์ฉ๋ฒ:
product = Product(99.99)
print(product.price) # ์ถ๋ ฅ: 99.99
try:
product.price = -10
except ValueError as e:
print(e) # ์ถ๋ ฅ: Value must be between 0 and 1000
์ฌ๊ธฐ์ `Sized` ๋์คํฌ๋ฆฝํฐ๋ `Product` ํด๋์ค์ `price` ์์ฑ์ด 0์์ 1000 ์ฌ์ด์ ์ซ์์ธ์ง ๊ฒ์ฆํฉ๋๋ค. ์ด๋ ์ ํ ๊ฐ๊ฒฉ์ด ํฉ๋ฆฌ์ ์ธ ๋ฒ์ ๋ด์ ์ ์ง๋๋๋ก ๋ณด์ฅํฉ๋๋ค.
์์ 3: ์ฝ๊ธฐ ์ ์ฉ ์์ฑ
๋น-๋ฐ์ดํฐ ๋์คํฌ๋ฆฝํฐ๋ฅผ ์ฌ์ฉํ์ฌ ์ฝ๊ธฐ ์ ์ฉ ์์ฑ์ ๋ง๋ค ์ ์์ต๋๋ค. `__get__` ๋ฉ์๋๋ง ์ ์ํจ์ผ๋ก์จ ์ฌ์ฉ์๊ฐ ์์ฑ์ ์ง์ ์์ ํ๋ ๊ฒ์ ๋ฐฉ์งํ ์ ์์ต๋๋ค:
class ReadOnly:
def __init__(self, name):
self.name = name
def __get__(self, instance, owner):
if instance is None:
return self
return instance._private_value # ๋น๊ณต๊ฐ ์์ฑ์ ์ ๊ทผ
class Circle:
radius = ReadOnly('radius')
def __init__(self, radius):
self._private_value = radius # ๊ฐ์ ๋น๊ณต๊ฐ ์์ฑ์ ์ ์ฅ
# ์ฌ์ฉ๋ฒ:
circle = Circle(5)
print(circle.radius) # ์ถ๋ ฅ: 5
try:
circle.radius = 10 # ์ด๊ฒ์ *์๋ก์ด* ์ธ์คํด์ค ์์ฑ์ ์์ฑํฉ๋๋ค!
print(circle.radius) # ์ถ๋ ฅ: 10
print(circle.__dict__) # ์ถ๋ ฅ: {'_private_value': 5, 'radius': 10}
except AttributeError as e:
print(e) # ์๋ก์ด ์ธ์คํด์ค ์์ฑ์ด ๋์คํฌ๋ฆฝํฐ๋ฅผ ๊ฐ๋ ธ๊ธฐ ๋๋ฌธ์ ์ด๊ฒ์ ํธ๋ฆฌ๊ฑฐ๋์ง ์์ ๊ฒ์
๋๋ค.
์ด ์๋๋ฆฌ์ค์์ `ReadOnly` ๋์คํฌ๋ฆฝํฐ๋ `Circle` ํด๋์ค์ `radius` ์์ฑ์ ์ฝ๊ธฐ ์ ์ฉ์ผ๋ก ๋ง๋ญ๋๋ค. `circle.radius`์ ์ง์ ํ ๋นํด๋ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ง ์๊ณ , ๋์ ๋์คํฌ๋ฆฝํฐ๋ฅผ ๊ฐ๋ฆฌ๋(shadowing) ์๋ก์ด ์ธ์คํด์ค ์์ฑ์ด ์์ฑ๋๋ค๋ ์ ์ ์ ์ํ์ธ์. ํ ๋น์ ์ง์ ์ผ๋ก ๋ง์ผ๋ ค๋ฉด `__set__`์ ๊ตฌํํ๊ณ `AttributeError`๋ฅผ ๋ฐ์์์ผ์ผ ํฉ๋๋ค. ์ด ์์ ๋ ๋ฐ์ดํฐ ๋์คํฌ๋ฆฝํฐ์ ๋น-๋ฐ์ดํฐ ๋์คํฌ๋ฆฝํฐ ๊ฐ์ ๋ฏธ๋ฌํ ์ฐจ์ด์ ํ์์ ๊ฒฝ์ฐ ์ด๋ป๊ฒ ์๋์์ด ๋ฐ์ํ ์ ์๋์ง๋ฅผ ๋ณด์ฌ์ค๋๋ค.
์์ 4: ์ง์ฐ๋ ๊ณ์ฐ (Lazy Evaluation)
๋์คํฌ๋ฆฝํฐ๋ ๋ํ ๊ฐ์ด ์ฒ์ ์ ๊ทผ๋ ๋๋ง ๊ณ์ฐ๋๋ ์ง์ฐ ํ๊ฐ(lazy evaluation)๋ฅผ ๊ตฌํํ๋ ๋ฐ ์ฌ์ฉ๋ ์ ์์ต๋๋ค:
import time
class LazyProperty:
def __init__(self, func):
self.func = func
self.name = func.__name__
def __get__(self, instance, owner):
if instance is None:
return self
value = self.func(instance)
instance.__dict__[self.name] = value # ๊ฒฐ๊ณผ๋ฅผ ์บ์ํจ
return value
class DataProcessor:
@LazyProperty
def expensive_data(self):
print("Calculating expensive data...")
time.sleep(2) # ๊ธด ๊ณ์ฐ ์๋ฎฌ๋ ์ด์
return [i for i in range(1000000)]
# ์ฌ์ฉ๋ฒ:
processor = DataProcessor()
print("Accessing data for the first time...")
start_time = time.time()
data = processor.expensive_data # ์ด๊ฒ์ด ๊ณ์ฐ์ ํธ๋ฆฌ๊ฑฐํฉ๋๋ค
end_time = time.time()
print(f"Time taken for first access: {end_time - start_time:.2f} seconds")
print("Accessing data again...")
start_time = time.time()
data = processor.expensive_data # ์ด๊ฒ์ ์บ์๋ ๊ฐ์ ์ฌ์ฉํฉ๋๋ค
end_time = time.time()
print(f"Time taken for second access: {end_time - start_time:.2f} seconds")
The `LazyProperty` ๋์คํฌ๋ฆฝํฐ๋ `expensive_data`์ ๊ณ์ฐ์ ์ฒ์ ์ ๊ทผ๋ ๋๊น์ง ์ง์ฐ์ํต๋๋ค. ์ดํ์ ์ ๊ทผ์ ์บ์๋ ๊ฒฐ๊ณผ๋ฅผ ๊ฒ์ํ์ฌ ์ฑ๋ฅ์ ํฅ์์ํต๋๋ค. ์ด ํจํด์ ๊ณ์ฐ์ ์๋นํ ์์์ด ํ์ํ๊ณ ํญ์ ํ์ํ์ง๋ ์์ ์์ฑ์ ์ ์ฉํฉ๋๋ค.
๊ณ ๊ธ ๋์คํฌ๋ฆฝํฐ ๊ธฐ์
๊ธฐ๋ณธ ์์ ๋ฅผ ๋์ด์, ๋์คํฌ๋ฆฝํฐ ํ๋กํ ์ฝ์ ๋ ๊ณ ๊ธ ๊ฐ๋ฅ์ฑ์ ์ ๊ณตํฉ๋๋ค:
๋์คํฌ๋ฆฝํฐ ๊ฒฐํฉํ๊ธฐ
๋์คํฌ๋ฆฝํฐ๋ฅผ ๊ฒฐํฉํ์ฌ ๋ ๋ณต์กํ ์์ฑ ๋์์ ๋ง๋ค ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, `Typed` ๋์คํฌ๋ฆฝํฐ์ `Sized` ๋์คํฌ๋ฆฝํฐ๋ฅผ ๊ฒฐํฉํ์ฌ ์์ฑ์ ๋ํด ํ์ ๊ณผ ๋ฒ์ ์ ์ฝ ์กฐ๊ฑด์ ๋ชจ๋ ๊ฐ์ ํ ์ ์์ต๋๋ค.
class ValidatedProperty:
def __init__(self, name, expected_type, min_value=None, max_value=None):
self.name = name
self.expected_type = expected_type
self.min_value = min_value
self.max_value = max_value
def __get__(self, instance, owner):
if instance is None:
return self
return instance.__dict__[self.name]
def __set__(self, instance, value):
if not isinstance(value, self.expected_type):
raise TypeError(f"Expected {self.expected_type}, got {type(value)}")
if self.min_value is not None and value < self.min_value:
raise ValueError(f"Value must be at least {self.min_value}")
if self.max_value is not None and value > self.max_value:
raise ValueError(f"Value must be at most {self.max_value}")
instance.__dict__[self.name] = value
class Employee:
salary = ValidatedProperty('salary', int, min_value=0, max_value=1000000)
def __init__(self, salary):
self.salary = salary
# ์์
employee = Employee(50000)
print(employee.salary)
try:
employee.salary = -1000
except ValueError as e:
print(e)
try:
employee.salary = "abc"
except TypeError as e:
print(e)
๋์คํฌ๋ฆฝํฐ์ ํจ๊ป ๋ฉํํด๋์ค ์ฌ์ฉํ๊ธฐ
๋ฉํํด๋์ค๋ ํน์ ๊ธฐ์ค์ ์ถฉ์กฑํ๋ ํด๋์ค์ ๋ชจ๋ ์์ฑ์ ๋์คํฌ๋ฆฝํฐ๋ฅผ ์๋์ผ๋ก ์ ์ฉํ๋ ๋ฐ ์ฌ์ฉ๋ ์ ์์ต๋๋ค. ์ด๋ ์์ฉ๊ตฌ ์ฝ๋๋ฅผ ํฌ๊ฒ ์ค์ด๊ณ ํด๋์ค ์ ๋ฐ์ ๊ฑธ์ณ ์ผ๊ด์ฑ์ ๋ณด์ฅํ ์ ์์ต๋๋ค.
class DescriptorMetaclass(type):
def __new__(cls, name, bases, attrs):
for attr_name, attr_value in attrs.items():
if isinstance(attr_value, Descriptor):
attr_value.name = attr_name # ์์ฑ ์ด๋ฆ์ ๋์คํฌ๋ฆฝํฐ์ ์ฃผ์
return super().__new__(cls, name, bases, attrs)
class Descriptor:
def __get__(self, instance, owner):
if instance is None:
return self
return instance.__dict__[self.name]
def __set__(self, instance, value):
instance.__dict__[self.name] = value
class UpperCase(Descriptor):
def __set__(self, instance, value):
if not isinstance(value, str):
raise TypeError("Value must be a string")
instance.__dict__[self.name] = value.upper()
class MyClass(metaclass=DescriptorMetaclass):
name = UpperCase()
# ์ฌ์ฉ ์์ :
obj = MyClass()
obj.name = "john doe"
print(obj.name) # ์ถ๋ ฅ: JOHN DOE
๋์คํฌ๋ฆฝํฐ ์ฌ์ฉ์ ์ํ ๋ชจ๋ฒ ์ฌ๋ก
๋์คํฌ๋ฆฝํฐ ํ๋กํ ์ฝ์ ํจ๊ณผ์ ์ผ๋ก ์ฌ์ฉํ๋ ค๋ฉด ๋ค์ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๊ณ ๋ คํ์ญ์์ค:
- ๋ณต์กํ ๋ก์ง์ ๊ฐ์ง ์์ฑ ๊ด๋ฆฌ์ ๋์คํฌ๋ฆฝํฐ๋ฅผ ์ฌ์ฉํ์ญ์์ค: ๋์คํฌ๋ฆฝํฐ๋ ์ ์ฝ ์กฐ๊ฑด์ ๊ฐ์ ํ๊ฑฐ๋, ๊ณ์ฐ์ ์ํํ๊ฑฐ๋, ์์ฑ์ ์ ๊ทผํ๊ฑฐ๋ ์์ ํ ๋ ์ฌ์ฉ์ ์ ์ ๋์์ ๊ตฌํํด์ผ ํ ๋ ๊ฐ์ฅ ๊ฐ์น๊ฐ ์์ต๋๋ค.
- ๋์คํฌ๋ฆฝํฐ๋ฅผ ์ง์ค๋๊ณ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ๊ฒ ์ ์งํ์ญ์์ค: ํน์ ์์ ์ ์ํํ๋๋ก ๋์คํฌ๋ฆฝํฐ๋ฅผ ์ค๊ณํ๊ณ ์ฌ๋ฌ ํด๋์ค์์ ์ฌ์ฌ์ฉํ ์ ์์ ๋งํผ ์ผ๋ฐ์ ์ผ๋ก ๋ง๋์ญ์์ค.
- ๋จ์ํ ๊ฒฝ์ฐ์๋ property() ์ฌ์ฉ์ ๋์์ผ๋ก ๊ณ ๋ คํ์ญ์์ค: ๋ด์ฅ `property()` ํจ์๋ ๊ธฐ๋ณธ์ ์ธ getter, setter, deleter ๋ฉ์๋๋ฅผ ๊ตฌํํ๊ธฐ ์ํ ๋ ๊ฐ๋จํ ๊ตฌ๋ฌธ์ ์ ๊ณตํฉ๋๋ค. ๋ ๊ณ ๊ธ ์ ์ด๋ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ๋ก์ง์ด ํ์ํ ๋ ๋์คํฌ๋ฆฝํฐ๋ฅผ ์ฌ์ฉํ์ญ์์ค.
- ์ฑ๋ฅ์ ์ ์ํ์ญ์์ค: ๋์คํฌ๋ฆฝํฐ ์ ๊ทผ์ ์ง์ ์ ์ธ ์์ฑ ์ ๊ทผ์ ๋นํด ์ค๋ฒํค๋๋ฅผ ์ถ๊ฐํ ์ ์์ต๋๋ค. ์ฝ๋์ ์ฑ๋ฅ์ด ์ค์ํ ๋ถ๋ถ์์๋ ๋์คํฌ๋ฆฝํฐ์ ๊ณผ๋ํ ์ฌ์ฉ์ ํผํ์ญ์์ค.
- ๋ช ํํ๊ณ ์ค๋ช ์ ์ธ ์ด๋ฆ์ ์ฌ์ฉํ์ญ์์ค: ๋์คํฌ๋ฆฝํฐ์ ๋ชฉ์ ์ ๋ช ํํ๊ฒ ๋ํ๋ด๋ ์ด๋ฆ์ ์ ํํ์ญ์์ค.
- ๋์คํฌ๋ฆฝํฐ๋ฅผ ์ฒ ์ ํ ๋ฌธ์ํํ์ญ์์ค: ๊ฐ ๋์คํฌ๋ฆฝํฐ์ ๋ชฉ์ ๊ณผ ๊ทธ๊ฒ์ด ์์ฑ ์ ๊ทผ์ ์ด๋ป๊ฒ ์ํฅ์ ๋ฏธ์น๋์ง ์ค๋ช ํ์ญ์์ค.
์ ์ญ์ ๊ณ ๋ ค์ฌํญ ๋ฐ ๊ตญ์ ํ
์ ์ญ์ ์ธ ๋งฅ๋ฝ์์ ๋์คํฌ๋ฆฝํฐ๋ฅผ ์ฌ์ฉํ ๋ ๋ค์ ์์๋ค์ ๊ณ ๋ คํ์ญ์์ค:
- ๋ฐ์ดํฐ ์ ํจ์ฑ ๊ฒ์ฌ ๋ฐ ์ง์ญํ: ๋ฐ์ดํฐ ์ ํจ์ฑ ๊ฒ์ฌ ๊ท์น์ด ๋ค๋ฅธ ๋ก์ผ์ผ์ ์ ํฉํ์ง ํ์ธํ์ญ์์ค. ์๋ฅผ ๋ค์ด, ๋ ์ง ๋ฐ ์ซ์ ํ์์ ๊ตญ๊ฐ๋ง๋ค ๋ค๋ฆ ๋๋ค. ์ง์ญํ ์ง์์ ์ํด `babel`๊ณผ ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ์ ๊ณ ๋ คํ์ญ์์ค.
- ํตํ ์ฒ๋ฆฌ: ๊ธ์ ์ ๊ฐ์น๋ฅผ ๋ค๋ฃฐ ๊ฒฝ์ฐ, ๋ค๋ฅธ ํตํ์ ํ์จ์ ์ฌ๋ฐ๋ฅด๊ฒ ์ฒ๋ฆฌํ๊ธฐ ์ํด `moneyed`์ ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ญ์์ค.
- ์๊ฐ๋: ๋ ์ง์ ์๊ฐ์ ๋ค๋ฃฐ ๋ ์๊ฐ๋๋ฅผ ์ธ์ํ๊ณ ์๊ฐ๋ ๋ณํ์ ์ฒ๋ฆฌํ๊ธฐ ์ํด `pytz`์ ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ญ์์ค.
- ๋ฌธ์ ์ธ์ฝ๋ฉ: ํนํ ํ ์คํธ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃฐ ๋ ์ฝ๋๊ฐ ๋ค๋ฅธ ๋ฌธ์ ์ธ์ฝ๋ฉ์ ์ฌ๋ฐ๋ฅด๊ฒ ์ฒ๋ฆฌํ๋์ง ํ์ธํ์ญ์์ค. UTF-8์ ๋๋ฆฌ ์ง์๋๋ ์ธ์ฝ๋ฉ์ ๋๋ค.
๋์คํฌ๋ฆฝํฐ์ ๋์
๋์คํฌ๋ฆฝํฐ๋ ๊ฐ๋ ฅํ์ง๋ง ํญ์ ์ต์์ ํด๊ฒฐ์ฑ ์ ์๋๋๋ค. ๊ณ ๋ คํด ๋ณผ ๋งํ ๋ช ๊ฐ์ง ๋์์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- `property()`: ๊ฐ๋จํ getter/setter ๋ก์ง์ ๊ฒฝ์ฐ, `property()` ํจ์๊ฐ ๋ ๊ฐ๊ฒฐํ ๊ตฌ๋ฌธ์ ์ ๊ณตํฉ๋๋ค.
- `__slots__`: ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ ์ค์ด๊ณ ๋์ ์์ฑ ์์ฑ์ ๋ฐฉ์งํ๋ ค๋ฉด `__slots__`๋ฅผ ์ฌ์ฉํ์ญ์์ค.
- ์ ํจ์ฑ ๊ฒ์ฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ: `marshmallow`์ ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ฅผ ์ ์ธ์ ์ผ๋ก ์ ์ํ๊ณ ์ ํจ์ฑ์ ๊ฒ์ฌํ๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค.
- ๋ฐ์ดํฐํด๋์ค: ํ์ด์ฌ 3.7+์ ๋ฐ์ดํฐํด๋์ค๋ `__init__`, `__repr__`, `__eq__`์ ๊ฐ์ด ์๋์ผ๋ก ์์ฑ๋๋ ๋ฉ์๋๋ฅผ ๊ฐ์ง ํด๋์ค๋ฅผ ๊ฐ๊ฒฐํ๊ฒ ์ ์ํ๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค. ๋ฐ์ดํฐ ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ์ํด ๋์คํฌ๋ฆฝํฐ๋ ์ ํจ์ฑ ๊ฒ์ฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๊ฒฐํฉํ ์ ์์ต๋๋ค.
๊ฒฐ๋ก
ํ์ด์ฌ ๋์คํฌ๋ฆฝํฐ ํ๋กํ ์ฝ์ ํด๋์ค์์ ์์ฑ ์ ๊ทผ๊ณผ ๋ฐ์ดํฐ ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ๊ด๋ฆฌํ๋ ๋ฐ ์ ์ฉํ ๋๊ตฌ์ ๋๋ค. ๊ทธ ํต์ฌ ๊ฐ๋ ๊ณผ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ์ดํดํจ์ผ๋ก์จ ๋ ๊น๋ํ๊ณ , ๊ฒฌ๊ณ ํ๋ฉฐ, ์ ์ง๋ณด์ํ๊ธฐ ์ฌ์ด ์ฝ๋๋ฅผ ์์ฑํ ์ ์์ต๋๋ค. ๋ชจ๋ ์์ฑ์ ๋์คํฌ๋ฆฝํฐ๊ฐ ํ์ํ์ง๋ ์๊ฒ ์ง๋ง, ์์ฑ ์ ๊ทผ๊ณผ ๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ์ ๋ํ ์ธ๋ฐํ ์ ์ด๊ฐ ํ์ํ ๋ ํ์์ ์ ๋๋ค. ๋์คํฌ๋ฆฝํฐ์ ์ด์ ๊ณผ ์ ์ฌ์ ์ธ ์ค๋ฒํค๋๋ฅผ ๋น๊ต ํ๊ฐํ๊ณ , ์ ์ ํ ๋ ๋์์ ์ธ ์ ๊ทผ ๋ฐฉ์์ ๊ณ ๋ คํ๋ ๊ฒ์ ์์ง ๋ง์ญ์์ค. ๋์คํฌ๋ฆฝํฐ์ ํ์ ๋ฐ์๋ค์ฌ ํ์ด์ฌ ํ๋ก๊ทธ๋๋ฐ ๊ธฐ์ ์ ํ ๋จ๊ณ ๋์ด์ฌ๋ฆฌ๊ณ ๋ ์ ๊ตํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ์ญ์์ค.